deferred class CD_TEXT
-- A raster text using a font with styles. The position the text is drawn 
-- depends on the text alignment attribute.
--
-- The library has at least 4 standard typefaces: "System" (which depends on 
-- the driver and platform), "Courier" (mono spaced with serif), "Times" 
-- (proportional with serif) and "Helvetica" (proportional without serif). Each 
-- typeface can have some styles: Plain, Bold, Italic and a combination of Bold 
-- and Italic. As an alternative to the standard typefaces, you can use other 
-- typefaces or native driver typefaces with the function "set_native_font", but
-- they may work in a reduced set of drivers.
--
-- You may retrieve the dimensions of the selected font with function 
-- "get_font_dim". Also you may retrieve the bounding box of a specific text 
-- before drawing by using the "get_text_size" and "get_text_box" functions.
--
-- The text is drawn using a reference point; you can change the alignment 
-- relative to this point using the "set_text_aligment" function. 

inherit
	CANVAS_DRAW

feature {ANY}

	-- Operations

	draws_text (x, y: INTEGER; text: STRING)
		-- Draws a text in the position (x,y) according to the current font and 
		-- text alignment. It expects an ANSI string. Can have line breaks.
		do
			int_canvas_text (cnvs, x, y, get_pointer(text.to_c))
		end

	draws_text_real (x, y: REAL_64; text: STRING)
		-- Like "draws_text" but with real coordinates.
		do
			int_canvas_c_double_text (cnvs, x, y, get_pointer(text.to_c))
		end

	wd_draws_text (x, y: REAL_64; text: STRING)
		-- Like "draws_text" but with World coordinates.
		do
			int_wd_canvas_text (cnvs, x, y, get_pointer(text.to_c))
		end

	-- Attributes

	set_font_typeface (typeface: STRING)
		-- The font type can be one of the standard type faces or other driver 
		-- dependent type face. Since font face names are not a standard between 
		-- drivers, a few names are specially handled to improve application 
		-- portability. If you want to use names that work for all systems we 
		-- recommend using: "Courier", "Times" and "Helvetica".
		-- Default: System.
		do
			int_canvas_font(cnvs, get_pointer(typeface.to_c), -1, 0)
		end

	get_font_typeface: STRING
		local
			t, s, z: POINTER
			str: STRING
		do
			int_canvas_get_font (cnvs, t, s, z)
			create str.make_from_c(t)
			Result := str
		end

	set_font_styles (styles: INTEGER)
		-- Defines the style of the font. Can be a combination of:
		--
		-- 0 = Plain
		-- 1 = Bold
		-- 2 = Italic
		-- 4 = Underline
		-- 8 = Strikeout
		--
		-- Only the Windows and PDF drivers support underline and strikeout.
		-- For example to define Bold and Italic, use 1|2 (bitwise logical 
		-- inclusive). Default: 0 (Plain).
		local
			p: POINTER
		do
			int_canvas_font(cnvs, p, styles, 0)
		end

	get_font_styles: INTEGER
		local
			p, si: POINTER
			s: INTEGER
		do
			int_canvas_get_font (cnvs, p, $s, si)
			Result := s
		end

	set_font_size (size: INTEGER)
		-- The size is provided in points (1/72 inch) or in pixels (using negative
		-- values).
		-- Default: 12.
		local
			p: POINTER
		do
			int_canvas_font(cnvs, p, -1, size)
		end

	get_font_size: INTEGER
		local
			p, st: POINTER
			s: INTEGER
		do
			int_canvas_get_font (cnvs, p, st, $s)
			Result := s
		end

	set_wd_font_size (size: REAL_64)
		-- Size is specified in millimeters, but is internally converted 
		-- to points.
		local
			p: POINTER
		do
			int_wd_canvas_font(cnvs, p, -1, size)
		end

	get_wd_font_styles: REAL_64
		local
			p, st: POINTER
			s: REAL_64
		do
			int_wd_canvas_get_font (cnvs, p, st, $s)
			Result := s
		end

	set_native_font (format: STRING)
		local
			p: POINTER
		do
			p := int_canvas_native_font(cnvs, get_pointer(format.to_c))
		end

	get_previous_native_font: STRING
		-- Selects a font based on a string description. The description can 
		-- depend on the driver and the platform, but a common definition is 
		-- available for all drivers. It does not need to be stored by the 
		-- application, as it is internally replicated by the library. The string 
		-- is case sensitive.
		--
		-- The common format definition is similar to the the Pango library 
		-- Font Description, used by GTK+2. It is defined as having 3 parts: 
		-- <font family>, <font styles> <font size>. For ex: "Times, Bold 18", 
		-- or "Arial,Helvetica, Italic Underline -24". The supported styles 
		-- include: Bold, Italic, Underline and Strikeout. Underline, 
		-- Strikeout, and negative pixel values are not supported by the 
		-- standard Pango Font Description. The Pango format include many 
		-- other definitions not supported by the CD format, they are just 
		-- ignored.
		--
		-- The IUP "FONT" attribute internal formats are also accepted in all 
		-- drivers and platforms.
		local
			p, s: POINTER
			str: STRING
		do
			s := int_canvas_native_font (cnvs, p)
			create str.make_from_c(s)
			Result := str
		end

	get_current_native_font: STRING
		local
			p: POINTER
			v, str: STRING
		do
			v := "(char*)CD_QUERY"
			p := int_canvas_native_font (cnvs, get_pointer(v.to_c))
			create str.make_from_c(p)
			Result := str
		end

	set_text_alignment (value: STRING)
		-- Defines the vertical and horizontal alignment of a text
		require
			is_valid_alignment(value)
		local
			v: INTEGER
		do
			v := int_canvas_text_alignment(cnvs, alignment_to_int(value))
		end

	get_text_alignment: STRING
		local
			i: INTEGER
		do
			i := int_canvas_text_alignment(cnvs, -1)
			Result := int_to_alignment(i)
		end

	set_text_orientation (angle: REAL_64)
		-- Defines the text orientation, which is an angle provided in degrees 
		-- relative to the horizontal line according to which the text is 
		-- drawn. Default: 0.	
		local
			i: REAL_64
		do
			i := int_canvas_text_orientation(cnvs, angle)
		end

	get_text_orientation: REAL_64
		do
			Result := int_canvas_text_orientation(cnvs, -1)
		end

	-- Properties

	get_font_dim: TUPLE[INTEGER, INTEGER, INTEGER, INTEGER]
   	-- Returns (in this order) the maximum width of a character, the 
		-- line's height, the ascent and descent of the characters of the 
		-- currently selected font. The line's height is the sum of the ascent 
		-- and descent of a given additional space (if this is the case).
		-- All values are given in pixels and are positive.
		local
			max_width, height, ascent, descent: INTEGER
		do
			int_canvas_get_font_dim(cnvs, $max_width, $height, $ascent, $descent)

			Result := [max_width, height, ascent, descent]
		end

	get_wd_font_dim: TUPLE[REAL_64, REAL_64, REAL_64, REAL_64]
		-- Returns (in this order) the maximum width of a character, the 
		-- line's height, the ascent and descent of the characters of the 
		-- currently selected font. The line's height is the sum of the ascent 
		-- and descent of a given additional space (if this is the case).
		-- All values are given in millimeters and are positive.
		local
			max_width, height, ascent, descent: REAL_64
		do
			int_wd_canvas_get_font_dim(cnvs, $max_width, $height, $ascent, $descent)

			Result := [max_width, height, ascent, descent]
		end

	get_text_size (text: STRING): TUPLE[INTEGER, INTEGER]
		-- Returns the text size independent from orientation.
		local
			w, h: INTEGER
		do
			int_canvas_get_text_size(cnvs, get_pointer(text.to_c), $w, $h)

			Result := [w, h]
		end

	get_wd_text_size (text: STRING): TUPLE[REAL_64, REAL_64]
		-- Returns the text size, in millimeters, independent from orientation.
		local
			w, h: REAL_64
		do
			int_wd_canvas_get_text_size(cnvs, get_pointer(text.to_c), $w, $h)

			Result := [w, h]
		end

	get_text_bounds (x, y: INTEGER; text: STRING): TUPLE[INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER]
		-- Returns the oriented bounding rectangle occupied by a text at a given 
		-- position. The rectangle has the same dimentions returned by feature
		-- get_text_size. The rectangle corners are returned in counter-clock 
		-- wise order starting with the bottom left corner, arranged 
		-- (x0,y0,x1,y1,x2,y2,x3,y3).	
		local
			p: POINTER
			points: MANAGED_POINTER
		do
			int_canvas_get_text_bounds(cnvs, x, y, get_pointer(text.to_c), p)

			create points.make_from_pointer(p, 8)

			Result := [points.read_integer_32(0), points.read_integer_32(1),
			  	        points.read_integer_32(2), points.read_integer_32(3),
				        points.read_integer_32(4), points.read_integer_32(5),
				        points.read_integer_32(6), points.read_integer_32(7)]
		end

	get_text_bounds_real (x, y: REAL_64; text: STRING): TUPLE[REAL_64, REAL_64, REAL_64, REAL_64, REAL_64, REAL_64, REAL_64, REAL_64]
		-- Like 'get_text_bounds' but with REAL_64 values.
		local
			p: POINTER
			points: MANAGED_POINTER
		do
			int_canvas_c_double_get_text_bounds(cnvs, x, y, get_pointer(text.to_c), p)

			create points.make_from_pointer(p, 8)

			Result := [points.read_real_64(0), points.read_real_64(1),
			           points.read_real_64(2), points.read_real_64(3),
			           points.read_real_64(4), points.read_real_64(5),
			           points.read_real_64(6), points.read_real_64(7)]
		end

	get_wd_text_bounds (x, y: REAL_64; text: STRING): TUPLE[REAL_64, REAL_64, REAL_64, REAL_64, REAL_64, REAL_64, REAL_64, REAL_64]
		-- Like 'get_text_bounds' but using World Coordinates.
		local
			p: POINTER
			points: MANAGED_POINTER
		do
			int_wd_canvas_get_text_bounds(cnvs, x, y, get_pointer(text.to_c), p)

			create points.make_from_pointer(p, 8)

			Result := [points.read_real_64(0), points.read_real_64(1),
			           points.read_real_64(2), points.read_real_64(3),
				        points.read_real_64(4), points.read_real_64(5),
				        points.read_real_64(6), points.read_real_64(7)]
		end

	get_text_box (x, y: INTEGER; text: STRING): TUPLE[INTEGER, INTEGER, INTEGER, INTEGER]
		-- Returns the horizontal bounding rectangle occupied by a text at a 
		-- given position. If orientation is not 0 then its area is always larger 
		-- than the area of the rectangle returned by 'get_text_bounds'.
		local
			xmin, xmax, ymin, ymax: INTEGER
		do
			int_canvas_get_text_box(cnvs, x, y, get_pointer(text.to_c), $xmin, $xmax, $ymin, $ymax)

			Result := [xmin, xmax, ymin, ymax]
		end

	get_text_box_real (x, y: REAL_64; text: STRING): TUPLE[REAL_64, REAL_64, REAL_64, REAL_64]
		-- Like 'get_text_box' but using REAL_64 values.
		local
			xmin, xmax, ymin, ymax: REAL_64
		do
			int_canvas_c_double_get_text_box(cnvs, x, y, get_pointer(text.to_c), $xmin, $xmax, $ymin, $ymax)

			Result := [xmin, xmax, ymin, ymax]
		end

	get_wd_text_box (x, y: REAL_64; text: STRING): TUPLE[REAL_64, REAL_64, REAL_64, REAL_64]
		-- Like 'get_text_box' but using World Coordinates.
		local
			xmin, xmax, ymin, ymax: REAL_64
		do
			int_wd_canvas_get_text_box(cnvs, x, y, get_pointer(text.to_c), $xmin, $xmax, $ymin, $ymax)

			Result := [xmin, xmax, ymin, ymax]
		end

	-- Validations
	
	is_valid_style (style: STRING): BOOLEAN
		do
			if style.is_equal("CD_PLAIN") or
				style.is_equal("CD_BOLD") or
				style.is_equal("CD_ITALIC") or
				style.is_equal("CD_UNDERLINE") or
				style.is_equal("CD_STRIKEOUT") then
				Result := True
			else
				Result := False
			end
		end

	is_valid_alignment (value: STRING): BOOLEAN
		do
			if value.is_equal("CD_NORTH") or
				value.is_equal("CD_SOUTH") or
				value.is_equal("CD_EAST") or
				value.is_equal("CD_WEST") or
				value.is_equal("CD_NORTH_EAST") or
				value.is_equal("CD_NORTH_WEST") or
				value.is_equal("CD_SOUTH_EAST") or
				value.is_equal("CD_SOUTH_WEST") or
				value.is_equal("CD_CENTER") or
				value.is_equal("CD_BASE_LEFT") or
				value.is_equal("CD_BASE_CENTER") or
				value.is_equal("CD_BASE_RIGHT") then
				Result := True
			else
				Result := False
			end
		end
	
feature {NONE}

	-- Convert

	styles_to_int (styles: ARRAY[STRING]): INTEGER
		local
			i, x: INTEGER
			style: STRING
		do
			i := 0

			from
				x := 0
			invariant
				valid_style: is_valid_style (styles.item(x))
         until
				x = styles.count
         loop
				style := styles.item(x)
							
				if style.is_equal("CD_PLAIN") then
					i := i | 0
				elseif style.is_equal("CD_BOLD") then
					i := i | 1
				elseif style.is_equal("CD_ITALIC") then
					i := i | 2
				elseif style.is_equal("CD_UNDERLINE") then
					i := i | 4
				elseif style.is_equal("CD_STRIKEOUT") then
					i := i | 8
				end

				x := x + 1
			end

			Result := i
		end

	alignment_to_int (value: STRING): INTEGER
		do
			if value.is_equal("CD_NORTH") then
				Result := 0
			elseif value.is_equal("CD_SOUTH") then
				Result := 1
			elseif value.is_equal("CD_EAST") then
				Result := 2
			elseif value.is_equal("CD_WEST") then
				Result := 3
			elseif value.is_equal("CD_NORTH_EAST") then
				Result := 4
			elseif value.is_equal("CD_NORTH_WEST") then
				Result := 5
			elseif value.is_equal("CD_SOUTH_EAST") then
				Result := 6
			elseif value.is_equal("CD_SOUTH_WEST") then
				Result := 7
			elseif value.is_equal("CD_CENTER") then
				Result := 8
			elseif value.is_equal("CD_BASE_LEFT") then
				Result := 9
			elseif value.is_equal("CD_BASE_CENTER") then
				Result := 10
			elseif value.is_equal("CD_BASE_RIGHT") then
				Result := 11
			end
		end

	int_to_alignment (value: INTEGER): STRING
		do
			if value.is_equal(0) then
				Result := "CD_NORTH"
			elseif value.is_equal(1) then
				Result := "CD_SOUTH"
			elseif value.is_equal(2) then
				Result := "CD_EAST"
			elseif value.is_equal(3) then
				Result := "CD_WEST"
			elseif value.is_equal(4) then
				Result := "CD_NORTH_EAST"
			elseif value.is_equal(5) then
				Result := "CD_NORTH_WEST"
			elseif value.is_equal(6) then
				Result := "CD_SOUTH_EAST"
			elseif value.is_equal(7) then
				Result := "CD_SOUTH_WEST"
			elseif value.is_equal(8) then
				Result := "CD_CENTER"
			elseif value.is_equal(9) then
				Result := "CD_BASE_LEFT"
			elseif value.is_equal(10) then
				Result := "CD_BASE_CENTER"
			elseif value.is_equal(11) then
				Result := "CD_BASE_RIGHT"
			else
				Result := "CD_NORTH"
			end
		end

	-- Internals

	int_canvas_text (wgt: POINTER; x, y: INTEGER; text: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasText ($wgt, $x, $y, $text);"
      end

	int_canvas_c_double_text (wgt: POINTER; x, y: REAL_64; text: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdfCanvasText ($wgt, $x, $y, $text);"
      end

	int_wd_canvas_text (wgt: POINTER; x, y: REAL_64; text: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"wdCanvasText ($wgt, $x, $y, $text);"
      end

	int_canvas_font (wgt, f: POINTER; tf, fs: INTEGER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasFont ($wgt, $f, $tf, $fs);"
      end

	int_wd_canvas_font (wgt, f: POINTER; tf: INTEGER; fs: REAL_64)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"wdCanvasFont ($wgt, $f, $tf, $fs);"
      end

	int_canvas_get_font (wgt, f, tf, fs: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasGetFont ($wgt, $f, $tf, $fs);"
      end

	int_wd_canvas_get_font (wgt, f, tf, fs: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"wdCanvasGetFont ($wgt, $f, $tf, $fs);"
      end

	int_canvas_native_font (wgt, sf: POINTER): POINTER
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"return cdCanvasNativeFont ($wgt, $sf);"
      end

	int_canvas_text_alignment (wgt: POINTER; algn: INTEGER): INTEGER
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"return cdCanvasTextAlignment ($wgt, $algn);"
      end

	int_canvas_text_orientation (wgt: POINTER; ang: REAL_64): REAL_64
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"return cdCanvasTextOrientation ($wgt, $ang);"
      end

	int_canvas_get_font_dim (wgt, mw, h, a, d: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasGetFontDim ($wgt, $mw, $h, $a, $d);"
      end

	int_wd_canvas_get_font_dim (wgt, mw, h, a, d: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"wdCanvasGetFontDim ($wgt, $mw, $h, $a, $d);"
      end

	int_canvas_get_text_size (wgt, text, w, h: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasGetTextSize ($wgt, $text, $w, $h);"
      end

	int_wd_canvas_get_text_size (wgt, text, w, h: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"wdCanvasGetTextSize ($wgt, $text, $w, $h);"
      end

	int_canvas_get_text_bounds (wgt: POINTER; x, y: INTEGER; text, r: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasGetTextBounds ($wgt, $x, $y, $text, $r);"
      end

	int_canvas_c_double_get_text_bounds (wgt: POINTER; x, y: REAL_64; text, r: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdfCanvasGetTextBounds ($wgt, $x, $y, $text, $r);"
      end

	int_wd_canvas_get_text_bounds (wgt: POINTER; x, y: REAL_64; text, r: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"wdCanvasGetTextBounds ($wgt, $x, $y, $text, $r);"
      end

	int_canvas_get_text_box (wgt: POINTER; x, y: INTEGER; text, xmin, xmax, ymin, ymax: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasGetTextBox ($wgt, $x, $y, $text, $xmin, $xmax, $ymin, $ymax);"
      end

	int_canvas_c_double_get_text_box (wgt: POINTER; x, y: REAL_64; text, xmin, xmax, ymin, ymax: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdfCanvasGetTextBox ($wgt, $x, $y, $text, $xmin, $xmax, $ymin, $ymax);"
      end

	int_wd_canvas_get_text_box (wgt: POINTER; x, y: REAL_64; text, xmin, xmax, ymin, ymax: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"wdCanvasGetTextBox ($wgt, $x, $y, $text, $xmin, $xmax, $ymin, $ymax);"
      end
	
end

-- The MIT License (MIT)

-- Copyright (c) 2017, 2019 by German A. Arias

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in 
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
